﻿using S7.Net;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace SCADA_SANEST.Models
{
    public enum DeviceType
    {
        Npc1,
        Npc2,
        Npc3,
        Hsl3,
        Hbt4
        // ...
    }

    public class PlcDeviceStatus : INotifyPropertyChanged
    {
        public string Name { get; }
        public DeviceType Type { get; }

        private string _ip;
        public string Ip
        {
            get => _ip;
            set
            {
                if (_ip != value)
                {
                    _ip = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Ip)));
                    RecreatePlcClient();
                }
            }
        }

        private Plc _client;
        public Plc Client => _client;

        private bool _isConnected;
        public bool IsConnected
        {
            get => _isConnected;
            set
            {
                if (_isConnected != value)
                {
                    _isConnected = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsConnected)));
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StatusBrush)));
                }
            }
        }

        public Brush StatusBrush => IsConnected ? Brushes.Green : Brushes.Red;
        public ObservableCollection<PlcSignal> Signals { get; } = new ObservableCollection<PlcSignal>();

        public PlcDeviceStatus(string name, string ip, DeviceType type)
        {
            Name = name;
            Ip = ip;
            Type = type;
        }

        public object ReadValue(string address, PlcDataType type)
        {
            if (_client == null || !_client.IsConnected)
                return null;

            try
            {
                var rawValue = _client.Read(address);
                switch (type)
                {
                    case PlcDataType.Bool:
                        return Convert.ToBoolean(rawValue);
                    case PlcDataType.Int:
                        return Convert.ToInt16(rawValue);
                    case PlcDataType.Word:
                        return Convert.ToUInt16(rawValue);
                    case PlcDataType.DInt:
                        return Convert.ToInt32(rawValue);
                    case PlcDataType.Real:
                        return rawValue is uint u ? BitConverter.ToSingle(BitConverter.GetBytes(u), 0) : 0f;
                    default:
                        return null;
                }
            }
            catch
            {
                return null;
            }
        }

        private void RecreatePlcClient()
        {
            _client?.Close();
            _client = new Plc(CpuType.S71200, _ip, 0, 1);
        }

        public bool Connect()
        {
            if (_client == null)
                RecreatePlcClient();

            try
            {
                _client.Open();
                IsConnected = _client.IsConnected;
                return IsConnected;
            }
            catch
            {
                IsConnected = false;
                return false;
            }
        }

        public void Disconnect()
        {
            try
            {
                _client?.Close();
            }
            catch { }
            finally
            {
                IsConnected = false;
            }
        }

        // -------------------- Thêm phần Polling --------------------
        private CancellationTokenSource _cancellationTokenSource;
        private Task _pollingTask;

        public void StartPolling()
        {
            if (_pollingTask == null)
            {
                _cancellationTokenSource = new CancellationTokenSource();
                _pollingTask = Task.Run(async () =>
                {
                    while (!_cancellationTokenSource.Token.IsCancellationRequested)
                    {
                        try
                        {
                            if (_client == null || !_client.IsConnected)
                            {
                                Connect(); // Thử kết nối lại nếu chưa kết nối
                            }

                            if (_client != null && _client.IsConnected)
                            {
                                ReadAllSignals();
                            }
                        }
                        catch (Exception ex)
                        {
                            IsConnected = false;
                            // TODO: log lỗi
                        }

                        await Task.Delay(500, _cancellationTokenSource.Token);
                    }
                }, _cancellationTokenSource.Token);
            }
        }


        public void StopPolling()
        {
            _cancellationTokenSource?.Cancel();
            _pollingTask = null;
        }

        private void ReadAllSignals()
        {
            if (_client == null || !_client.IsConnected)
                return;

            foreach (var signal in Signals)
            {
                var value = ReadValue(signal.Address, signal.Type);
                signal.Value = value; // cập nhật giá trị cho UI binding
            }
        }
        // TODO: gọi tới SignalMap tương ứng với Type (Npc1/Npc2/...) để đọc hết các giá trị
        // ví dụ:
        // foreach (var signal in SignalMaps[Type])
        // {
        //     var value = ReadValue(signal.Address, signal.DataType);
        //     signal.Value = value;
        // }
        // -----------------------------------------------------------

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
